﻿using System;
using System.Collections.Generic;
using System.Threading;
using System.Linq;
using System.Text;
using OpenQA.Selenium;
using OpenQA.Selenium.Firefox;
using OpenQA.Selenium.Support.UI;
using System.Runtime.Serialization;
using System.Text.RegularExpressions;
using NUnit.Framework;
using SupportLibrary;

namespace TestFramework
{
    public class TestClassInstance
    {
        IWebDriver driver;
        
        private string baseURL;
        private StringBuilder verificationErrors;
        

        private Page pageCommon;
        private WebControl controlCommon;
        private WebButton buttonCommon;
        private TextBox textboxCommon;
        private DropdownList dropListCommon;
        private Combobox comboboxCommon;
        private By currentBy= null;
        

        public TestClassInstance(Dictionary<string,string> config)
        {
            

            driver = new FirefoxDriver();

            

            baseURL = Res.Page.BaseUrl;
            
            verificationErrors = new StringBuilder();
            pageCommon = new Page(driver, baseURL);
            controlCommon = new WebControl(driver, currentBy);
             buttonCommon = new WebButton(driver,currentBy);
             textboxCommon= new TextBox(driver,currentBy);
             dropListCommon= new DropdownList(driver,currentBy);
             comboboxCommon= new Combobox(driver,currentBy);
        }



        [Automation]
        public void UpdateBalance(string mobile, Decimal balance)
        {
           DBLinq.Instance().UpdateBalance(mobile, balance);
        }

        [Automation]
        public void VerifyBalance(string mobile, Decimal expectedBalance)
        {
            DBLinq.Instance().VerifyBalance(mobile, expectedBalance);
        }

        [Automation]
        public void CurrentTarget(string target)
        {
            currentBy = WebControl.ParseTarget(target);
        }


        [Automation]
        public void NavigateToUrl(string url)
        {
            pageCommon.NavigateUrl(url);
        }

        [Automation]
        public void VerifyTextPresent(string text)
        {
            controlCommon.VerifyTextPresent(text);
        }

        [Automation]
        public void ClickButton(string target)
        {
            controlCommon.Click(target);
        }

        
        
        [Automation]
        public void InputText(string target,string text)
        {
            textboxCommon.InputText(target,text);
        }

        [Automation]
        public void SelectByValue(string target, string value)
        {
            dropListCommon.SelectByValue(target, value);
        }

        [Automation]
        public void SelectByIndex(string target, int ix)
        {
            dropListCommon.SelectByIndex(ix);
        }

        [Automation]
        public void SelectByText(string target, string text)
        {
            dropListCommon.SelectByText(target, text);
        }   
        

        ~TestClassInstance()
        {
            if(driver!=null)
            driver.Quit();
        }


    }


    public class DropdownList : WebControl
    { 
      public DropdownList(IWebDriver driver, By by)
            : base(driver, by)
        { 

        }

      public void SelectByText(string target, string text)
      {
          this.mby = ParseTarget(target);
          SelectByText(text);
      }
      public void SelectByText(string text)
      {
          
          try
          {
              if (this.WaitForElement())
              {
                  new SelectElement(mdriver.FindElement(this.mby)).SelectByText(text);
              }
              else
              {
                  throw new AutoException(Res.Err.control_notfound);
              }
          }
          catch (Exception ex)
          {
              if(ex.GetType() !=typeof(AutoException))
              throw new AutoException(Res.Err.text_notfound + text);
          }

         
      }

      public void SelectByIndex(string target, int ix)
      {
          this.mby = ParseTarget(target);
          SelectByIndex(ix);
      }

      public void SelectByIndex(int ix)
      {
          try
          {
              if (this.WaitForElement())
              {
                  new SelectElement(mdriver.FindElement(this.mby)).SelectByIndex(ix);
              }
              else
              {
                  throw new AutoException(Res.Err.control_notfound);
              }
          }
          catch (Exception ex)
          {
              if(ex.GetType() != typeof(AutoException))
              throw new AutoException(Res.Err.index_notfound + ix.ToString());  
          }
      }

      public void SelectByValue(string target, string value)
      {
          this.mby = ParseTarget(target);
          SelectByValue(value);
      }

      public void SelectByValue(string value)
      {
          try
          {
              if (this.WaitForElement())
              {
                  new SelectElement(mdriver.FindElement(this.mby)).SelectByText(value);

              }
              else
              {
                  throw new AutoException(Res.Err.control_notfound);
              }
          }
          catch(Exception ex)
          {
              if(ex.GetType() !=typeof(AutoException))
              throw new AutoException(Res.Err.value_notfound + value);  
          }
      }

    }

    public class Combobox : WebControl
    {
         public Combobox(IWebDriver driver, By by)
            : base(driver, by)
        { 

        }
         public void SelectText(string target, string text)
         {
             
                 this.mby = ParseTarget(target);
                 SelectText(text);
             
             
         }

        public void SelectText(string text)
        {
            try
            {
                this.WaitForElement();
                new SelectElement(this.mdriver.FindElement(mby)).SelectByText(text);
            }
            catch {
                throw new AutoException(Res.Err.text_notfound + text);  
            }

                
        }
    }

    public class TextBox : WebControl
    {

        public TextBox(IWebDriver driver, By by)
            : base(driver, by)
        { 

        }

        public void InputText(string target, string text)
        {
            this.mby = ParseTarget(target);
            InputText(text);
        }
        public void InputText(string text)
        {
            try
            {
                this.WaitForElement();
                this.mdriver.FindElement(this.mby).Clear();
                this.mdriver.FindElement(this.mby).SendKeys(text);
            }
            catch (Exception ex)
            {
                throw new AutoException(Res.Err.control_notfound);  
            }
        }
        
    }


    public class WebButton : WebControl
    {

        public WebButton(IWebDriver driver, By by)
            : base(driver, by)
        {

        }

      

    }

    public class WebControl
    {
        protected By mby;
        protected IWebDriver mdriver;
        //private ILog log = LogManager.GetLogger("MainWindow");

        public WebControl(IWebDriver driver)
        {
            mdriver = driver;
        }

        public WebControl(IWebDriver driver, By by)
        {
            mdriver = driver;
            mby = by;
        }


        public By By {
            get { return mby ;}
            set{ mby = value;}
        }

        public static By ParseTarget(string target)
        {
            try
            {
                int signal = target.IndexOf("//");

                Console.WriteLine("input string:" + target);
                if (signal == 0)
                {
                    //Console.WriteLine("xpath :" + target);
                    return By.XPath(target.Trim());
                }

                signal = target.IndexOf("name");
                if (signal == 0)
                {
                    string[] targetvalues = target.Split('=');
                    if (targetvalues.Length == 2)
                    {
                        //Console.WriteLine("name :" + targetvalues[1]);
                        return By.Name(targetvalues[1].Trim());
                    }

                }

                signal = target.IndexOf("css");

                if (signal == 0)
                {
                    string[] targetvalues = target.Split('=');
                    if (targetvalues.Length == 2)
                    {
                        //Console.WriteLine("css :" + targetvalues[1]);
                        return By.CssSelector(targetvalues[1].Trim());

                    }
                }

                signal = target.IndexOf("id");
                if (signal == 0)
                {

                    string[] targetvalues = target.Split('=');
                    if (targetvalues.Length == 2)
                    {
                        //Console.WriteLine("id :" + targetvalues[1]);
                        return By.Id(targetvalues[1].Trim());

                    }
                }
                
                signal = target.IndexOf("link");
                if (signal == 0)
                {
                    
                    string[] targetvalues = target.Split('=');
                    if (targetvalues.Length == 2)
                    {
                        //Console.WriteLine("id :" + targetvalues[1]);
                        return By.LinkText(targetvalues[1].Trim());

                    }
                }               
            }
            catch (Exception ex)
            {
                if(ex.GetType()!= typeof(AutoException))
                throw new AutoException(Res.Err.control_notfound + target);
                
            }
            return null;
        }


        public void Click(string target)
        {
                mby = ParseTarget(target);
                this.Click();



        }

        public void Click()
        {
            try
            {
                WaitForElement();
                mdriver.FindElement(mby).Click();
                Thread.Sleep(3000);
            }
            catch (Exception ex)
            {
                //throw new Exception(ex.Message);
                if (ex.GetType() != typeof(AutoException))
                throw new AutoException(  Res.Err.control_notfound);

            }
        }

        public void VerifyTextPresent(string text)
        {
            string[] splittext = text.Split(' ');
            bool found = true;

                foreach(string str in splittext){
                    if (!mdriver.PageSource.Contains(str))
                        found = false;
                 
                }

                if (!found)
                {
                    throw new AutoException(Res.Err.text_notfound + text);
                }
            
            
        }

        public bool WaitForElementNotPresent(string target)
        {
            mby = ParseTarget(target);
            return WaitForElementNotPresent();

        }

        public bool WaitForElementNotPresent()
        {
            for (int second = 0; ; second++)
            {
                if (second >= 60) return false;
                try
                {
                    if (!IsElementPresent()) return true;
                }
                catch (Exception)
                { }
                Thread.Sleep(1000);
            }

        }

        public bool IsElementPresent(string target)
        {
            mby = ParseTarget(target);
            return IsElementPresent();
        }

        public bool IsElementPresent()
        {
            try
            {
                mdriver.FindElement(mby);
                return true;
            }
            catch (NoSuchElementException)
            {
                return false;
            }
        }

        public bool WaitForElement(string target)
        {
            mby = ParseTarget(target);
            return WaitForElement();
        }
        public bool WaitForElement()
        {
            int num = 0;
            while (true)
            {
                Thread.Sleep(1000);
                num++;
                if (IsElementPresent() || num == 90)
                    return true;
            }

            return false;
        }

    }


    public  class Page
    { 
        
        protected IWebDriver mdriver;
        protected string murl;

        //private ILog log = LogManager.GetLogger("MainWindow");
        

        public Page(IWebDriver driver, string url)
        {
            mdriver = driver;
            murl = url;
            
        }
        public void NavigateUrl(string url)
        {
            murl = url;
            NavigateUrl();
        }

        public void NavigateUrl()
        { 
            //mdriver.Navigate.
            try
            {
                mdriver.Navigate().GoToUrl(murl);
            }
            catch (Exception ex)
            {
                throw new AutoException(murl + Res.Err.url_notexist + murl);
            }
            
        }
    }

    
}
